namespace ShapesLib
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Text;

    /// <summary>
    /// Class to draw polygon shapes.
    /// </summary>
    public class Polygon : Shape
    {
        #region Members
        /// <summary>
        /// Points list.
        /// </summary>
        private List<Point> points = new List<Point>();
        #endregion
        
        #region Constructor(s)
        /// <summary>
        /// Initializes a new instance of the <see cref="Polygon"/> class.
        /// </summary>
        public Polygon()
        {
            this.points = new List<Point>();
            this.FillColor = Color.WhiteSmoke;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Polygon"/> class.
        /// </summary>
        /// <param name="points">The points.</param>
        public Polygon(ICollection<Point> points)
        {
            this.points = new List<Point>(points);
            this.FillColor = Color.WhiteSmoke;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the points.
        /// </summary>
        /// <value>
        /// The points.
        /// </value>
        public List<Point> Points
        {
            get { return this.points; }
            set { this.points = value; }
        }

        /// <summary>
        /// Gets the point count.
        /// </summary>
        public int PointCount
        {
            get
            {
                return this.points.Count;
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="System.Drawing.Point"/> at the specified index.
        /// </summary>
        /// <param name="index">Index of the point</param>
        /// <returns>Point of index</returns>
        public Point this[int index]
        {
            get { return this.points[index]; }
            set { this.points[index] = value; }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Adds the point.
        /// </summary>
        /// <param name="point">The point.</param>
        public void AddPoint(Point point)
        {
            this.points.Add(point);
        }

        /// <summary>
        /// Removes the point at.
        /// </summary>
        /// <param name="index">The index.</param>
        public void RemovePointAt(int index)
        {
            this.points.RemoveAt(index);
        }

        /// <summary>
        /// Translates the specified dx.
        /// </summary>
        /// <param name="dx">The dx.</param>
        /// <param name="dy">The dy.</param>
        public override void Translate(int dx, int dy)
        {
            for (int i = 0; i < this.points.Count; i++)
            {
                this.points[i] = Point.Add(this.points[i], new Size(dx, dy));
            }
        }

        /// <summary>
        /// Points the in shape.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <returns>True if point is in shape.</returns>
        public override bool PointInShape(int x, int y)
        {
            Point point = new Point(x, y);

            GraphicsPath path = new GraphicsPath();
            path.Reset();

            Point[] pointarr = new Point[this.points.Count];
            for (int i = 0; i < this.points.Count; i++)
            {
                pointarr[i] = this.points[i];
            }

            path.AddPolygon(pointarr);
            return path.IsVisible(point);
        }

        /// <summary>
        /// Draws the specified g.
        /// </summary>
        /// <param name="g">The g.</param>
        public override void Draw(Graphics g)
        {
            Point[] points = new Point[this.PointCount];
            byte[] types = new byte[this.PointCount];

            for (int i = 0; i < this.PointCount; i++)
            {
                points[i] = this.points[i];
                types[i] = (byte)PathPointType.Line;
            }

            types[0] = (byte)PathPointType.Start;
            types[this.PointCount - 1] = (byte)PathPointType.CloseSubpath;

            g.FillPolygon(new SolidBrush(FillColor), points);
            Pen pen = new Pen(PenColor, PenWidth);
            g.DrawPolygon(pen, points);
        }

        /// <summary>
        /// Draws for creation.
        /// </summary>
        /// <param name="g">The g.</param>
        public override void DrawForCreation(Graphics g)
        {
            Pen pen = new Pen(PenColor, PenWidth);

            for (int i = 0; i < this.PointCount - 1; i++)
            {
                g.DrawLine(pen, this.Points[i], this.Points[i + 1]);
            }
        }

        /// <summary>
        /// Scales the specified factor.
        /// </summary>
        /// <param name="factor">The factor.</param>
        public override void Scale(double factor)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }
}